{
 "cells": [
  {
   "cell_type": "code",
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:27.503406Z",
     "start_time": "2025-03-06T10:55:27.496561Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)\n",
    "np.random.seed(seed)\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.3.1+cu121\n",
      "cuda:0\n"
     ]
    }
   ],
   "execution_count": 24
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 数据准备",
   "id": "3a371093b35c22dc"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:28.049283Z",
     "start_time": "2025-03-06T10:55:27.638179Z"
    }
   },
   "cell_type": "code",
   "source": [
    "cleaned_df = pd.read_csv(\"imdb_processed.csv\")\n",
    "print(cleaned_df.shape)  # (50000, 2), 50000条评论, 2列\n",
    "\n",
    "# 随机打乱数据，取训练集和测试集\n",
    "np.random.seed(seed)  #随机\n",
    "cleaned_df = cleaned_df.sample(frac=1).reset_index(drop=True)  #打乱，frac=1表示全部打乱（frac是比例，reset_index(drop=True)是重新索引\n",
    "with open(\"imdb_train.txt\", \"w\", encoding=\"utf8\") as file:  # 保存训练集\n",
    "    for line in cleaned_df.processed.values[:25000]:  #只保存了processed列，即评论文本，没有保存label列\n",
    "        file.write(line.lower() + \"\\n\")  #变为小写，token数量少一些\n",
    "\n",
    "with open(\"imdb_test.txt\", \"w\", encoding=\"utf8\") as file:  # 保存测试集\n",
    "    for line in cleaned_df.processed.values[25000:]:\n",
    "        file.write(line.lower() + \"\\n\")"
   ],
   "id": "d86f71c5d902bde2",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(50000, 2)\n"
     ]
    }
   ],
   "execution_count": 25
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:43.282246Z",
     "start_time": "2025-03-06T10:55:28.049283Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 学习bpe分词(很慢,学一次就好)\n",
    "# -i 选择学习的文件\n",
    "# -o 核心输出文件,分词需要用到imdb_bpe_code\n",
    "# --write-vocabulary 字典输出文件\n",
    "# -s 词表大小\n",
    "!subword-nmt learn-joint-bpe-and-vocab -i ./imdb_train.txt -o ./imdb_bpe_code --write-vocabulary ./imdb_bpe_vocab -s 20000\n"
   ],
   "id": "d06c43077cb01ee4",
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "  0%|          | 0/20000 [00:00<?, ?it/s]\n",
      "  0%|          | 6/20000 [00:00<06:11, 53.82it/s]\n",
      "  0%|          | 12/20000 [00:00<05:52, 56.65it/s]\n",
      "  0%|          | 24/20000 [00:00<04:00, 83.17it/s]\n",
      "  0%|          | 42/20000 [00:00<02:48, 118.77it/s]\n",
      "  0%|          | 65/20000 [00:00<02:06, 157.02it/s]\n",
      "  1%|          | 105/20000 [00:00<01:23, 237.71it/s]\n",
      "  1%|          | 161/20000 [00:00<00:58, 341.28it/s]\n",
      "  1%|1         | 226/20000 [00:00<00:45, 432.31it/s]\n",
      "  1%|1         | 294/20000 [00:00<00:39, 501.65it/s]\n",
      "  2%|1         | 382/20000 [00:01<00:31, 614.43it/s]\n",
      "  2%|2         | 479/20000 [00:01<00:27, 721.08it/s]\n",
      "  3%|2         | 586/20000 [00:01<00:24, 802.28it/s]\n",
      "  3%|3         | 698/20000 [00:01<00:21, 891.76it/s]\n",
      "  4%|4         | 804/20000 [00:01<00:20, 933.43it/s]\n",
      "  5%|4         | 947/20000 [00:01<00:17, 1068.78it/s]\n",
      "  5%|5         | 1082/20000 [00:01<00:16, 1151.46it/s]\n",
      "  6%|6         | 1218/20000 [00:01<00:15, 1207.28it/s]\n",
      "  7%|6         | 1372/20000 [00:01<00:14, 1303.89it/s]\n",
      "  8%|7         | 1534/20000 [00:01<00:13, 1397.31it/s]\n",
      "  9%|8         | 1703/20000 [00:02<00:12, 1484.36it/s]\n",
      "  9%|9         | 1899/20000 [00:02<00:11, 1602.08it/s]\n",
      " 10%|#         | 2090/20000 [00:02<00:10, 1679.30it/s]\n",
      " 12%|#1        | 2311/20000 [00:02<00:09, 1831.80it/s]\n",
      " 13%|#2        | 2568/20000 [00:02<00:08, 2042.51it/s]\n",
      " 14%|#4        | 2845/20000 [00:02<00:07, 2251.71it/s]\n",
      " 16%|#5        | 3157/20000 [00:02<00:06, 2507.08it/s]\n",
      " 18%|#7        | 3501/20000 [00:02<00:05, 2772.80it/s]\n",
      " 20%|#9        | 3952/20000 [00:02<00:04, 3279.89it/s]\n",
      " 22%|##2       | 4495/20000 [00:02<00:03, 3911.53it/s]\n",
      " 24%|##4       | 4887/20000 [00:03<00:06, 2208.33it/s]\n",
      " 26%|##5       | 5194/20000 [00:03<00:07, 2005.75it/s]\n",
      " 27%|##7       | 5456/20000 [00:03<00:07, 1990.59it/s]\n",
      " 28%|##8       | 5698/20000 [00:03<00:07, 2011.25it/s]\n",
      " 30%|##9       | 5930/20000 [00:03<00:06, 2040.78it/s]\n",
      " 31%|###       | 6169/20000 [00:03<00:06, 2116.06it/s]\n",
      " 32%|###2      | 6450/20000 [00:04<00:05, 2269.63it/s]\n",
      " 34%|###3      | 6739/20000 [00:04<00:05, 2419.73it/s]\n",
      " 35%|###5      | 7056/20000 [00:04<00:04, 2592.08it/s]\n",
      " 37%|###7      | 7417/20000 [00:04<00:04, 2814.56it/s]\n",
      " 39%|###9      | 7825/20000 [00:04<00:03, 3158.63it/s]\n",
      " 41%|####      | 8187/20000 [00:04<00:03, 3276.89it/s]\n",
      " 44%|####4     | 8894/20000 [00:04<00:02, 4279.09it/s]\n",
      " 47%|####7     | 9431/20000 [00:04<00:03, 3365.70it/s]\n",
      " 49%|####9     | 9804/20000 [00:05<00:04, 2482.85it/s]\n",
      " 51%|#####     | 10107/20000 [00:05<00:04, 2173.79it/s]\n",
      " 52%|#####1    | 10365/20000 [00:05<00:04, 2005.13it/s]\n",
      " 53%|#####2    | 10593/20000 [00:05<00:04, 1889.00it/s]\n",
      " 54%|#####3    | 10799/20000 [00:05<00:05, 1826.35it/s]\n",
      " 55%|#####4    | 10992/20000 [00:05<00:04, 1810.25it/s]\n",
      " 56%|#####5    | 11180/20000 [00:06<00:04, 1818.13it/s]\n",
      " 57%|#####6    | 11373/20000 [00:06<00:04, 1830.03it/s]\n",
      " 58%|#####7    | 11588/20000 [00:06<00:04, 1898.72it/s]\n",
      " 59%|#####9    | 11801/20000 [00:06<00:04, 1957.23it/s]\n",
      " 60%|######    | 12034/20000 [00:06<00:03, 2055.27it/s]\n",
      " 61%|######1   | 12288/20000 [00:06<00:03, 2189.54it/s]\n",
      " 63%|######2   | 12565/20000 [00:06<00:03, 2345.09it/s]\n",
      " 64%|######4   | 12877/20000 [00:06<00:02, 2551.07it/s]\n",
      " 66%|######6   | 13237/20000 [00:06<00:02, 2824.36it/s]\n",
      " 68%|######8   | 13617/20000 [00:06<00:02, 3108.89it/s]\n",
      " 70%|#######   | 14093/20000 [00:07<00:01, 3578.90it/s]\n",
      " 73%|#######2  | 14562/20000 [00:07<00:02, 2680.34it/s]\n",
      " 74%|#######4  | 14869/20000 [00:07<00:02, 2216.13it/s]\n",
      " 76%|#######5  | 15128/20000 [00:07<00:02, 1978.04it/s]\n",
      " 77%|#######6  | 15353/20000 [00:07<00:02, 1872.89it/s]\n",
      " 78%|#######7  | 15558/20000 [00:07<00:02, 1814.39it/s]\n",
      " 79%|#######8  | 15751/20000 [00:08<00:02, 1793.30it/s]\n",
      " 80%|#######9  | 15946/20000 [00:08<00:02, 1811.11it/s]\n",
      " 81%|########  | 16150/20000 [00:08<00:02, 1857.29it/s]\n",
      " 82%|########1 | 16376/20000 [00:08<00:01, 1935.87it/s]\n",
      " 83%|########2 | 16587/20000 [00:08<00:01, 1968.62it/s]\n",
      " 84%|########4 | 16816/20000 [00:08<00:01, 2046.90it/s]\n",
      " 85%|########5 | 17061/20000 [00:08<00:01, 2160.53it/s]\n",
      " 87%|########6 | 17339/20000 [00:08<00:01, 2289.70it/s]\n",
      " 88%|########8 | 17601/20000 [00:08<00:01, 2368.31it/s]\n",
      " 89%|########9 | 17877/20000 [00:09<00:00, 2480.24it/s]\n",
      " 91%|######### | 18176/20000 [00:09<00:00, 2623.17it/s]\n",
      " 93%|#########3| 18600/20000 [00:09<00:00, 3081.99it/s]\n",
      " 95%|#########5| 19001/20000 [00:09<00:00, 3340.38it/s]\n",
      " 98%|#########7| 19516/20000 [00:09<00:00, 2420.90it/s]\n",
      " 99%|#########9| 19802/20000 [00:09<00:00, 1926.39it/s]\n",
      "100%|##########| 20000/20000 [00:10<00:00, 1999.29it/s]\n"
     ]
    }
   ],
   "execution_count": 26
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:49.655376Z",
     "start_time": "2025-03-06T10:55:43.282246Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 应用bpe分词,-c 指定 BPE 编码的配置文件\n",
    "!subword-nmt apply-bpe -c ./imdb_bpe_code -i ./imdb_train.txt -o ./imdb_train_bpe.txt\n",
    "!subword-nmt apply-bpe -c ./imdb_bpe_code -i ./imdb_test.txt -o ./imdb_test_bpe.txt"
   ],
   "id": "d6ad7b166859758f",
   "outputs": [],
   "execution_count": 27
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:49.698830Z",
     "start_time": "2025-03-06T10:55:49.655376Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 分词后的数据长什么样,与分词前imdb_train.txt进行对比来理解，@@ 是分词的标记，如果一个单词被分开，就会加上@@\n",
    "!head ./imdb_train_bpe.txt\n"
   ],
   "id": "6248c467f39fac00",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i really liked summer@@ slam due look arena , curtain look overall interesting reason . anyways , could one best summer@@ slam ever wwf lex luger main event yo@@ ko@@ z@@ una , time ok huge fat man v strong man i glad time changed . it terrible main event like every match luger terrible . other match card razor ramon v ted di@@ bi@@ ase , steiner brothers v heavenly bodies , shawn michaels v cur@@ t h@@ ening , event shawn named big monster body guard diesel , irs v - - kid , bre@@ t hart first take do@@ ink take jerry law@@ ler stuff har@@ ts law@@ ler always interesting , lud@@ vi@@ g bor@@ ga destroyed marty jan@@ ne@@ tty , undertaker took giant gonz@@ ale@@ z another terrible match , the smoking g@@ unn@@ s tat@@ an@@ ka took bam bam bi@@ ge@@ low head@@ shr@@ in@@ kers , yo@@ ko@@ z@@ una def@@ ended world title lex luger match boring terrible ending . however deserves\n",
      "not many television show appeal quite many different kind fan like farscape . . . i know youngster year old fan male female many different country think adore t . v miniseries . it element found almost every show t . v , character driven drama could australian soap opera yet episode science fact fiction would give even har@@ di@@ est trek@@ kie run money brain@@ bender stake ! wor@@ m@@ hole theory , time travel true equ@@ ational form . . . magnificent . it embrace culture map possibility endless multiple star therefore thousand planet choose . with broad scope would expected nothing would able keep illusion long , farscape really come element . . . it succeeds others failed , especially like star trek universe practically zero ka@@ os element ! they ran idea pretty quickly kept reha@@ shing ! over course season manage keep audience attention using good continuity constant character evolution multiple thread every episode unique personal touch camera specific certain character group within whole . this structure allows extremely large area subject matter loyalty for@@ ged broken many way many many issue . i happened see pilot premiere passing keep tuning see crichton would ever get girl , seeing television i delighted see available dvd i admit thing kept sane whilst i hour night shift developed chronic insomnia . . . farscape thing get extremely long night . . . do favour watch pilot see i mean . . . farscape comet\n",
      "the film quickly get major chase scene ever increasing destruction . the first really bad thing guy hijac@@ king steven seagal would beaten pulp seagal driving , probably would ended whole premise movie . it seems like decided make kind change movie plot , plan enjoy action , expect coherent plot . turn sense logic may , reduce chance getting headache . i give hope steven seagal trying move back towards type character portrayed popular movie .\n",
      "jane austen would definitely approve one ! gwyneth paltrow awesome job capturing attitude emma . she funny without excessively silly , yet elegant . she put convincing british accent british , maybe i best judge , fooled . . . also excellent sliding doors . . . i sometimes forget american ! . also brilliant jeremy northam sophie thompson phylli@@ da law emma thompson sister mother bates woman . they nearly steal show . . . ms . law even line ! highly recommended .\n",
      "expec@@ ta@@ tions somewhat high i went see movie , i thought steve carell could wrong coming great movie like anchorman , the year - old virgin , little miss sunshine . boy , i wrong . i start right movie certain point steve carell allowed steve carell . there handful moment film made laugh , due almost entirely given wi@@ ggle - room thing . he undoubtedly talented individual , shame signed turned , opinion , total train - wreck . with way , i discus went horri@@ fyingly wrong . the film begin dan burns , widower three girl considered na@@ tionally syndi@@ cated advice column . he pre@@ pa@@ res girl family reunion , extended relative gather time . the family high atop list thing make awful movie . no family behaves like . it almost transported pleasan@@ t@@ ville leave beaver . they caricature think family . it reach point become obnoxious simply frustrating . touch football , cross@@ word puzzle competition , family bow@@ ling , talent show are not how actual people behave . it almost sickening . another big flaw woman carell supposed falling . observing first scene steve carell like watching stroke victim trying rehab@@ ilit@@ ated . what i imagine supposed unique original woman come mildly retarded . it make think movie taking place another planet . i left theater wondering i saw . after thinking , i think much .\n",
      "i watched movie fairly regular basis life , never get old . for sni@@ de remark insult mostly david spade , tommy boy giant heart . and keep movie funny year . tommy callahan chris farley son big tom callahan brian den@@ ne@@ hy , master car part salesman , ridden life . but died dy wedding day , tommy learns company debt , bought ray z@@ al@@ in@@ sky dan ak@@ royd , owner huge car part company . so order save company , tommy go road sell company new brake pad . along ride , though choice , richard hayden david spade former classmate tommy big tom right - hand man . the movie ride chemistry two snl star real - life best friend chris farley david spade . the duo enough comic energy going power world . it big , dumb guy versus smart little guy . it work , scene un@@ forget@@ tably funny . farley spade actually decent dramatic actor well . although film primarily comedy , fair share drama , spade especially farley good making audience laugh . forgive , i talk chris farley little . i read biography the chris farley show a biography three acts , anyone care , understanding chris real life made movie special . chris farley genuinely good person struggled , ultimately failed conquer addiction . although first movie major role , best film . it really showed , much talent . knowing chris story add another layer movie , although make le funny . farley spade matched good screen cast . rob lowe suitably slimy tommy new brother , bo derek solid step - mother . brian den@@ ne@@ hy great big tom . den@@ ne@@ hy make easy believe father son . big tom crazy son , although smarter mature . dan ak@@ royd give one best performance z@@ al@@ in@@ sky , giving tommy hard truth behind advertising . julie warner also good tommy love interest , michelle . for , peter segal one great comedy director . he keep pace quick energetic , importantly , know make comedy funny . he be@@ labor joke , understands funny actor know allows . but segal go step . he give tommy boy friendly , almost nostalgic tone tug heart@@ strings genuinely ti@@ ckle f@@ unn@@ y@@ bone . critics like tommy boy . shame . a movie super sophisticated subver@@ sively intellectual funny god forbid farley spade forced muted comedy la the office . this great movie one - time favorite .\n",
      "for story hope highlighted tragic reality youth face . fav@@ ela rising draw one scary , un@@ safe unfair world show beautiful color moving music one man dedicated friend choose accept world change action art . an entertaining , interesting , emotional , aes@@ thetically beautiful film . i showed film numerous high school student well live neighborhood poverty gun violence enamored anderson , protagonist . i recommend film age due subtitle image death background .\n",
      "okay , i get purgatory thing first time i watched episode . it seemed like something significant going i put finger . this time costa me@@ sa fire tv really caught attention - helped i writing essay inferno ! but let see ha@@ s@@ n t discussed yet . . . a tw@@ op review mentioned tony flight stair go broken elevator . yeah , significant number lot reason , especially religious , one ya . on hun@@ ch i con@@ sulted wikipedia , guess dante divided level ? pur@@ gat@@ ori@@ o . exclu@@ ding ante - purgatory paradise . the stuff bottom stair . . . tony get . on allegedly random monk - slap scene . as soon monk appeared , fit perfectly place tony trying get purgatory . you tell got worried christian commercial death , disease , sin came , getting desperate christian heaven looking kinda i@@ ffy . by time meet monk thinking hey maybe guy help ? sound like contemplating religion e . g . budd@@ h@@ ism wondering path could take salvation . not tony necessarily literally thinking becoming buddhist , appears fin@@ ner@@ ty tried messed . that slap face basically tell tony quick fix - , , suddenly embrace budd@@ h@@ ism get . tony initially concerned getting heaven . but conference entrance , realizes going easy . at first i saw name v . driver license problem tony led sort double life , killing people sleeping around kept secret people . he feel free affair quasi - mel@@ fi kevin fin@@ ner@@ ty . he figure can fool people k@@ f card , like hotel recep@@ tionist , get purgatory . those helicopter - helicopter heaven ? - keeping track everything . after reading theory infin@@ ner@@ ty , though , seems like k@@ f identity reminder infinite different path tony could taken life . possibly along car joke involving infin@@ iti made sense otherwise . a@@ a@@ and point brain fi@@ zzle .\n",
      "i disappointed series . it lot cool graphic . the level detail went minimal , i always got feeling audience patron@@ ized - - lot seemed this extremely cool going explain detail get anyway . let show pretty picture entertain . the host would drop interesting - sounding word spar@@ tic@@ les super - sym@@ me@@ try without attempt explaining . we look wikipedia . furthermore , i know quite bit super@@ string la@@ yman i found explanation convoluted could much better . they could chosen much better example explain concept , instead , example used confusing obscu@@ red subject . additionally , i got sick repeti@@ tiveness . they could easily con@@ den@@ sed series one episode cut repetition . they must shown clip quantum caf time . the host kept saying thing . i remember many time said the universe made tiny little vibra@@ ting string . it like trying brain@@ wash u accepting super@@ string best thing since sliced bread . finally , show ended unpleasant sense competition fer@@ mil@@ ab cer@@ n , clearly biased towards fer@@ mil@@ ab . this supposed educational program quantum physic , whether us better europe vice versa ! i also felt part patron@@ izing - - audiences need see conflict remain interested . please . give little credit . overall , thumb -\n",
      "the first minute tin@@ sel@@ town finger te@@ e@@ tering remote , po@@ ised flick around watch something else . the premise two writer , luck , living self - stor@@ age - space bin mildly amusing , , painfully bland . the introduction character , played joe pan@@ to@@ li@@ ano - big deal movie guy , life park sleep la@@ v@@ atory , offered hope i decided give minute . and kri@@ sty swan@@ sons introduction budding film director borderline nymphomaniac , added bit spice . her solid acting performance raised presence beyond welcome eye - candy inclusion . ultimately , obvious low - budget impact film poorly shot scene , stu@@ t@@ tured pace slapstick handling certain moment . some favourite movie time low budget , whi@@ th@@ nail i one also deal guy dream , luck . however , money , actor save tin@@ sel@@ town terrible movie archive nu@@ dge could cult movie archive . i laughed loud scene involving joe pan@@ to@@ li@@ ano character . in particular , pen@@ ultimate scene terribly clichd , still funny , rich - - screwed - character house , story unravel@@ s towards final moment . i see tin@@ sel@@ town great stage play film - maker best translate celluloid , simply work i laughed loud scene one liner , i think first minute du@@ lled sens expectation degree i would laughed anything . unless stuck novelty coffee coaster , pick see bargain bucket .\n"
     ]
    }
   ],
   "execution_count": 28
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:50.901884Z",
     "start_time": "2025-03-06T10:55:49.698830Z"
    }
   },
   "cell_type": "code",
   "source": [
    "subwords = []\n",
    "with open(\"imdb_train_bpe.txt\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in file.readlines():\n",
    "        subwords.append(line.strip())\n",
    "\n",
    "with open(\"imdb_test_bpe.txt\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in file.readlines():\n",
    "        subwords.append(line.strip())\n",
    "\n",
    "cleaned_df[\"subwords10k\"] = subwords  # 保存分词后的结果\n",
    "cleaned_df[\"split\"] = [\"train\"] * 25000 + [\"test\"] * 25000  # 标记训练集和测试集\n",
    "cleaned_df.to_csv(\"imdb_subwords.csv\", index=False)  #把分词后的结果保存到csv文件"
   ],
   "id": "c0aff9b0835ac046",
   "outputs": [],
   "execution_count": 29
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:51.872124Z",
     "start_time": "2025-03-06T10:55:50.902134Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "\n",
    "# 随后加载数据集就从bpe分词的文件里加载\n",
    "class IMDBDataset(Dataset):\n",
    "    def __init__(self, mode=\"train\"):\n",
    "        df = pd.read_csv(\"imdb_subwords.csv\").query(\"split == '{}'\".format(mode))  # 加载训练集或测试集，query语句筛选\n",
    "        self.texts = df[\"subwords10k\"].values  # 评论文本\n",
    "        self.labels = df[\"label\"].values  # 评论标签\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.labels)\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        return self.texts[idx].split(), self.labels[idx]  # 返回文本和标签\n",
    "\n",
    "\n",
    "train_ds = IMDBDataset(\"train\")\n",
    "test_ds = IMDBDataset(\"test\")"
   ],
   "id": "a9d5dc26309c76ff",
   "outputs": [],
   "execution_count": 30
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:51.876389Z",
     "start_time": "2025-03-06T10:55:51.872124Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#载入词表，看下词表长度，词表就像英语字典\n",
    "word2idx = {\n",
    "    \"[PAD]\": 0,  # 填充 token\n",
    "    \"[BOS]\": 1,  # begin of sentence\n",
    "    \"[UNK]\": 2,  # 未知 token\n",
    "    \"[EOS]\": 3,  # end of sentence\n",
    "}\n",
    "idx2word = {value: key for key, value in word2idx.items()}\n",
    "print(idx2word)\n",
    "index = len(idx2word)  # 词表长度，现在为4\n"
   ],
   "id": "d753cde2a0eb369",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{0: '[PAD]', 1: '[BOS]', 2: '[UNK]', 3: '[EOS]'}\n"
     ]
    }
   ],
   "execution_count": 31
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:51.895233Z",
     "start_time": "2025-03-06T10:55:51.876389Z"
    }
   },
   "cell_type": "code",
   "source": [
    "threshold = 1  # 出现次数低于此的token舍弃\n",
    "with open(\"imdb_bpe_vocab\", \"r\", encoding=\"utf8\") as file:\n",
    "    for line in tqdm(file.readlines()):\n",
    "        token, counts = line.strip().split()\n",
    "        if int(counts) >= threshold:\n",
    "            word2idx[token] = index  # 加入词表\n",
    "            idx2word[index] = token  # 加入反向词典\n",
    "            index += 1\n",
    "\n",
    "vocab_size = len(word2idx)\n",
    "print(\"vocab_size: {}\".format(vocab_size))"
   ],
   "id": "790e3bac9f45355b",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/19684 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "f2ee4dae287c4d3fa718d771e75c7e22"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "vocab_size: 19688\n"
     ]
    }
   ],
   "execution_count": 32
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.443919Z",
     "start_time": "2025-03-06T10:55:51.896237Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 选择 max_length\n",
    "length_collect = {}\n",
    "for text, label in train_ds:\n",
    "    length = len(text)\n",
    "    length_collect[length] = length_collect.get(length, 0) + 1\n",
    "\n",
    "MAX_LENGTH = 500\n",
    "plt.bar(length_collect.keys(), length_collect.values())\n",
    "plt.axvline(MAX_LENGTH, label=\"max length\", c=\"gray\", ls=\":\")\n",
    "plt.legend()\n",
    "plt.show()"
   ],
   "id": "126ab50f442578a",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 33
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# Tokenizer",
   "id": "1a4a4d7aadfa849c"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.451707Z",
     "start_time": "2025-03-06T10:55:52.445923Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class Tokenizer:\n",
    "\n",
    "    def __init__(self, word2idx, idx2word, max_length=500, pad_idx=0, bos_idx=1, eos_idx=3, unk_idx=2):\n",
    "        self.word2idx = word2idx  #词表,单词到id\n",
    "        self.idx2word = idx2word  #词表，id到单词\n",
    "        self.max_length = max_length\n",
    "        self.pad_idx = pad_idx  #填充\n",
    "        self.bos_idx = bos_idx  #开始\n",
    "        self.eos_idx = eos_idx  #结束\n",
    "        self.unk_idx = unk_idx  #未知，未出现在最高频词表中的词\n",
    "\n",
    "    def encode(self, text_list, padding_first=False):\n",
    "        \"\"\"\n",
    "        将文本列表转化为索引列表\n",
    "        :param text_list:当前批次的文本列表\n",
    "        :param padding_first:是否padding加载前面\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        # 最大长度，句子长度小于500，取句子长度，大于500，取500，一个批次内的最大长度\n",
    "        max_length = min(self.max_length, 2 + max([len(text) for text in text_list]))\n",
    "        indices_list = []\n",
    "        for text in text_list:\n",
    "\n",
    "            #直接切片取前max_length-2个单词，然后加上bos和eos\n",
    "            indices = [self.bos_idx] + [self.word2idx.get(word, self.unk_idx) for word in text[:max_length - 2]] + [\n",
    "                self.eos_idx]\n",
    "            if padding_first:\n",
    "                # 填充0\n",
    "                indices = [self.pad_idx] * (max_length - len(indices)) + indices\n",
    "            else:\n",
    "                # 如果padding_first == False，则padding加载后面\n",
    "                indices = indices + [self.pad_idx] * (max_length - len(indices))\n",
    "            indices_list.append(indices)\n",
    "        return torch.tensor(indices_list)  #二维列表转化为tensor\n",
    "\n",
    "    def decode(self, indices_list, remove_bos=True, remove_eos=True, remove_pad=True, split=False):\n",
    "        \"\"\"\n",
    "        将索引列表转化为文本列表\n",
    "        :param indices_list:某批次的索引列表\n",
    "        :param remove_bos:移除开始符\n",
    "        :param remove_eos:移除结束符\n",
    "        :param remove_pad:移除填充符\n",
    "        :param split:分词\n",
    "        :return:\n",
    "        \"\"\"\n",
    "        # 生成文本列表\n",
    "        text_list = []\n",
    "        for indices in indices_list:\n",
    "            # 单词列表\n",
    "            text = []\n",
    "\n",
    "            # 循环遍历索引列表\n",
    "            for index in indices:\n",
    "\n",
    "                # id转化为单词\n",
    "                word = self.idx2word.get(index, \"[UNK]\")\n",
    "                # 移除开始符\n",
    "                if remove_bos and word == \"[BOS]\":\n",
    "                    continue\n",
    "                # 移除结束符\n",
    "                if remove_eos and word == \"[EOS]\":\n",
    "                    break\n",
    "                # 移除填充符\n",
    "                if remove_pad and word == \"[PAD]\":\n",
    "                    break\n",
    "                # 添加单词到文本列表\n",
    "                text.append(word)\n",
    "            # 合并单词列表为句子\n",
    "            text_list.append(\" \".join(text) if not split else text)\n",
    "        return text_list\n",
    "\n",
    "\n",
    "# 实例化Tokenizer\n",
    "tokenizer = Tokenizer(word2idx=word2idx, idx2word=idx2word)"
   ],
   "id": "2d1a0956f621d1e",
   "outputs": [],
   "execution_count": 34
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.456248Z",
     "start_time": "2025-03-06T10:55:52.451707Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 验证一下\n",
    "raw_text = [\"hello world\".split(), \"i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ \".split(),\n",
    "            \"this is a test\".split()]\n",
    "indices = tokenizer.encode(raw_text, padding_first=False)\n",
    "\n",
    "print(\"raw text-------------------\")\n",
    "for raw in raw_text:\n",
    "    print(raw)\n",
    "print(\"indices---------------\")\n",
    "for index in indices:\n",
    "    print(index)"
   ],
   "id": "c4e49cc35cdbbdab",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "raw text-------------------\n",
      "['hello', 'world']\n",
      "['i', 'really', 'liked', 'sum@@', 'mer@@', 'sla@@', 'm', 'due', 'look', 'a@@', 'ren@@', 'a', ',', 'cur@@']\n",
      "['this', 'is', 'a', 'test']\n",
      "indices---------------\n",
      "tensor([   1, 4869,   98,    3,    0,    0,    0,    0,    0,    0,    0,    0,\n",
      "           0,    0,    0,    0])\n",
      "tensor([   1,    6,   26,  381, 4267, 1871, 2427,  626,  646,   61,  344, 2063,\n",
      "          39,    5, 3034,    3])\n",
      "tensor([   1,   18,  387,   39, 1708,    3,    0,    0,    0,    0,    0,    0,\n",
      "           0,    0,    0,    0])\n"
     ]
    }
   ],
   "execution_count": 35
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.460759Z",
     "start_time": "2025-03-06T10:55:52.456248Z"
    }
   },
   "cell_type": "code",
   "source": [
    "decode_text = tokenizer.decode(indices.tolist(), remove_bos=False, remove_eos=False, remove_pad=False)\n",
    "print(\"decode text\")\n",
    "for decode in decode_text:\n",
    "    print(decode)"
   ],
   "id": "aa68cd72274465e4",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "decode text\n",
      "[BOS] hello world [EOS] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]\n",
      "[BOS] i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ [EOS]\n",
      "[BOS] this is a test [EOS] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD] [PAD]\n"
     ]
    }
   ],
   "execution_count": 36
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.465345Z",
     "start_time": "2025-03-06T10:55:52.461763Z"
    }
   },
   "cell_type": "code",
   "source": [
    "import re\n",
    "\n",
    "# 输入字符串\n",
    "text = \"i really liked sum@@ mer@@ sla@@ m due look a@@ ren@@ a , cur@@ \"\n",
    "\n",
    "# 使用正则表达式替换 \"@@ \" 为空字符串\n",
    "cleaned_text = re.sub(r'@@\\s*', '', text)\n",
    "\n",
    "print(cleaned_text)"
   ],
   "id": "350ca7cd8dfcb123",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i really liked summerslam due look arena , cur\n"
     ]
    }
   ],
   "execution_count": 37
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.473159Z",
     "start_time": "2025-03-06T10:55:52.465345Z"
    }
   },
   "cell_type": "code",
   "source": [
    "def collate_fct(batch):\n",
    "    \"\"\"\n",
    "    把字符串列表转化为tensor\n",
    "    :param batch: 一个包含多个样本的列表，每个样本是一个元组，包含文本和标签\n",
    "    :return: 返回处理后的文本列表和标签张量\n",
    "    \"\"\"\n",
    "    # 从batch中提取文本列表，每个样本的第一个元素是文本，类型为list\n",
    "    text_list = [item[0] for item in batch]\n",
    "    # 从batch中提取标签列表，每个样本的第二个元素是标签，类型为int\n",
    "    label_list = [item[1] for item in batch]\n",
    "    # 使用tokenizer对文本列表进行编码，并进行padding，最后转换为torch.int类型的张量\n",
    "    text_list = tokenizer.encode(text_list, padding_first=True).to(dtype=torch.int)\n",
    "    # 将标签列表转换为张量，并reshape为(-1, 1)的形状，最后转换为torch.float类型\n",
    "    return text_list, torch.tensor(label_list).reshape(-1, 1).to(dtype=torch.float)\n",
    "\n",
    "\n",
    "batch_size = 128\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, collate_fn=collate_fct)\n",
    "test_dl = DataLoader(test_ds, batch_size=batch_size, shuffle=False, collate_fn=collate_fct)"
   ],
   "id": "df2f9c2a9001461d",
   "outputs": [],
   "execution_count": 38
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 定义模型",
   "id": "d13f468c07077f71"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.484488Z",
     "start_time": "2025-03-06T10:55:52.474164Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class LSTM(nn.Module):\n",
    "    def __init__(self, embedding_dim=16, hidden_dim=64, vocab_size=vocab_size, num_layers=1, bidirectional=False):\n",
    "        super(LSTM, self).__init__()\n",
    "        self.embeding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True,\n",
    "                            bidirectional=bidirectional)\n",
    "        self.layer = nn.Linear(hidden_dim * (2 if bidirectional else 1), hidden_dim)\n",
    "        self.fc = nn.Linear(hidden_dim, 1)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.embeding(x)\n",
    "        # 通过LSTM层处理输入数据x，返回三个值：\n",
    "        # seq_output: 每个时间步的隐藏状态输出，形状为(batch_size, seq_len, hidden_dim * num_directions)\n",
    "        # hidden: 最后一个时间步的隐藏状态，形状为(num_layers * num_directions, batch_size, hidden_dim)\n",
    "        # cell: 最后一个时间步的细胞状态，形状为(num_layers * num_directions, batch_size, hidden_dim)\n",
    "        seq_output, (hidden, cell) = self.lstm(x)\n",
    "        x = seq_output[:, -1, :]\n",
    "        x = self.layer(x)\n",
    "        x = self.fc(x)\n",
    "        return x\n",
    "\n",
    "\n",
    "sample_inputs = torch.randint(0, vocab_size, (2, 128))\n",
    "\n",
    "print(\"{:=^80}\".format(\" 一层单向 LSTM \"))\n",
    "for key, value in LSTM().named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n",
    "print(\"{:=^80}\".format(\" 一层双向 LSTM \"))\n",
    "for key, value in LSTM(bidirectional=True).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "\n",
    "print(\"{:=^80}\".format(\" 两层单向 LSTM \"))\n",
    "for key, value in LSTM(num_layers=2).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n"
   ],
   "id": "b26d757c7b7fbb34",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================== 一层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 315008\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n",
      "================================== 一层双向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 315008\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "       lstm.weight_ih_l0_reverse        paramerters num: 4096\n",
      "       lstm.weight_hh_l0_reverse        paramerters num: 16384\n",
      "        lstm.bias_ih_l0_reverse         paramerters num: 256\n",
      "        lstm.bias_hh_l0_reverse         paramerters num: 256\n",
      "              layer.weight              paramerters num: 8192\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n",
      "================================== 两层单向 LSTM ===================================\n",
      "            embeding.weight             paramerters num: 315008\n",
      "           lstm.weight_ih_l0            paramerters num: 4096\n",
      "           lstm.weight_hh_l0            paramerters num: 16384\n",
      "            lstm.bias_ih_l0             paramerters num: 256\n",
      "            lstm.bias_hh_l0             paramerters num: 256\n",
      "           lstm.weight_ih_l1            paramerters num: 16384\n",
      "           lstm.weight_hh_l1            paramerters num: 16384\n",
      "            lstm.bias_ih_l1             paramerters num: 256\n",
      "            lstm.bias_hh_l1             paramerters num: 256\n",
      "              layer.weight              paramerters num: 4096\n",
      "               layer.bias               paramerters num: 64\n",
      "               fc.weight                paramerters num: 64\n",
      "                fc.bias                 paramerters num: 1\n"
     ]
    }
   ],
   "execution_count": 39
  },
  {
   "metadata": {},
   "cell_type": "markdown",
   "source": "# 训练模型",
   "id": "109bba3bc1476394"
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.488364Z",
     "start_time": "2025-03-06T10:55:52.484488Z"
    }
   },
   "cell_type": "code",
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)  # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        # 二分类\n",
    "        preds = logits > 0\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "\n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "id": "c29fb38fa4e184bb",
   "outputs": [],
   "execution_count": 40
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.492915Z",
     "start_time": "2025-03-06T10:55:52.488364Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "\n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "\n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "\n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "id": "3956756abba2d43d",
   "outputs": [],
   "execution_count": 41
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.497387Z",
     "start_time": "2025-03-06T10:55:52.493919Z"
    }
   },
   "cell_type": "code",
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "\n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else:\n",
    "            self.counter += 1\n",
    "\n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "id": "4d7630c6779e102b",
   "outputs": [],
   "execution_count": 42
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T10:55:52.502764Z",
     "start_time": "2025-03-06T10:55:52.497387Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# 训练\n",
    "def training(\n",
    "        model,\n",
    "        train_loader,\n",
    "        val_loader,\n",
    "        epoch,\n",
    "        loss_fct,\n",
    "        optimizer,\n",
    "        save_ckpt_callback=None,\n",
    "        early_stop_callback=None,\n",
    "        eval_step=500,\n",
    "):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "\n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits > 0\n",
    "\n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "\n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "\n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "\n",
    "                    # 1. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 2. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "\n",
    "    return record_dict"
   ],
   "id": "46225a31f31aed68",
   "outputs": [],
   "execution_count": 43
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T11:01:04.807784Z",
     "start_time": "2025-03-06T10:55:52.503768Z"
    }
   },
   "cell_type": "code",
   "source": [
    "epoch = 20\n",
    "\n",
    "model = LSTM()\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 (但是二分类)\n",
    "loss_fct = F.binary_cross_entropy_with_logits\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "# 1. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/imdb-lstm-subword\", save_step=len(train_dl),\n",
    "                                             save_best_only=True)\n",
    "# 2. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model,\n",
    "    train_dl,\n",
    "    test_dl,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    ")"
   ],
   "id": "1d3549bd4e612d0f",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/3920 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "cec26b5e799a40ec9fe31aeeb94d81d7"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 44
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T11:01:05.415770Z",
     "start_time": "2025-03-06T11:01:04.810421Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):\n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "plot_learning_curves(record, sample_step=10)  #横坐标是 steps"
   ],
   "id": "fb900eadd3a6bceb",
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ],
      "image/png": "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YmE6f/58YfO6du1araioyHWrrq7WWUaypeknn3wiLCMnTpwobkbLyMsuu0xYoLINZKdOnUwtIx944AHhsvLyyy9HlPXmQw89JFyODh8+LI41fszuTytXrhSvYwwDR3XtYTCW4QXmJj2Yl4ID5qbggLkp+ualiBZDDHuO82BzTwe2M+UeBNHMmjVrxGRjvN16660uG9NHH31UTBo8WU+bNk347KucOXNGTDLp6enC4vD2228Xk5kK94K48MILxTp69OghJrNIwWz8+Mb9HSQ8Sd99993CjpN/qFdffbWYlFSOHDmiXX755aLXBXvn/+xnP9MaGho8vq+RI0eK47dPnz66bbR3fvCDH2j5+fnis/F/cHysycmGwRgGb9LBWIYfmJvcYF4KDpibggPmpuibl2L4Hz+jXwAAAAAAAADQ7onYmiEAAAAAAAAAsANiCAAAAAAAABCVQAwBAAAAAAAAohKIIQAAAAAAAEBUAjEEAAAAAAAAiEoghgAAAAAAAABRCcQQAAAAAAAAICqBGAIAAAAAAABEJRBDAASJ2267ja666qq23g0AAABAgHkJAO9ADAEAAAAAAACiEoghAPzknXfeoeHDh1NKSgp17NiRpk+fTg888AAtXbqU3n//fYqJiRG3tWvXiuWPHz9ON9xwA3Xo0IFycnLoyiuvpCNHjnhcuXv88cepU6dOlJmZSXfddRfV19e34acEAADQXsC8BEDgxLfgvQBEHUVFRTR37lx69tln6eqrr6aKigpat24dzZs3j44dO0bl5eX0xhtviGV5gmloaKCZM2fSxIkTxXLx8fH061//mmbNmkXbt2+nxMREsezq1aspOTlZTFQ8Id1+++1iQvvNb37Txp8YAABAOIN5CYCWATEEgJ+TTmNjI11zzTWUn58vnuOrcQxfkaurq6OuXbu6lv/rX/9Kzc3N9Prrr4urcgxPSnw1jieYyy67TDzHk8/ixYspNTWVhg4dSk888YS4qvfkk09SbCwCuAAAAMzBvARAy8DRDIAfjBgxgqZNmyYmmuuvv55ee+01OnfunOXyX3/9NR04cIAyMjIoPT1d3PjKXG1tLR08eFC3Xp5wJHzFrrKyUqQyAAAAAFZgXgKgZSAyBIAfxMXF0apVq2j9+vW0cuVKeumll+iRRx6hTZs2mS7PE8eYMWPozTff9HiN87ABAACAloB5CYCWATEEgJ9wWsHkyZPFbeHChSIt4b333hMpBU1NTbplR48eTW+//TZ17txZFKDaXamrqakRKQ3Mxo0bxdW6nj17hvzzAAAAaN9gXgIgcJAmB4Af8JW2p556ir744gtRmPruu+/SqVOnaPDgwVRQUCCKT/fu3UunT58WRao33XQT5ebmCqceLlQ9fPiwyMm+99576dtvv3Wtlx167rjjDtq1axctX76cHnvsMVqwYAHysgEAANiCeQmAloHIEAB+wFfRPvvsM3rxxReFQw9fffvtb39Ll19+OY0dO1ZMKPyX0xDWrFlDF198sVj+wQcfFMWt7PLTo0cPkd+tXpHjx/3796eLLrpIFLuyM9CvfvWrNv2sAAAAwh/MSwC0jBhN07QWrgMA0AK4n8P58+dp2bJlbb0rAAAAAOYlEFUg1gkAAAAAAACISiCGAAAAAAAAAFEJ0uQAAAAAAAAAUQkiQwAAAAAAAICoBGIIAAAAAAAAEJVADAEAAAAAAACiEoghAAAAAAAAQFQCMQQAAAAAAACISiCGAAAAAAAAAFEJxBAAAAAAAAAgKoEYAgAAAAAAAEQlEEMAAAAAAAAAikb+P5+PIHz3imwxAAAAAElFTkSuQmCC"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 45
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-03-06T11:04:16.605057Z",
     "start_time": "2025-03-06T11:04:12.849527Z"
    }
   },
   "cell_type": "code",
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/imdb-lstm-subword/best.ckpt\", map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, test_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "id": "c02b346e31d04906",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.4165\n",
      "accuracy: 0.8563\n"
     ]
    }
   ],
   "execution_count": 46
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "30c1c2a2f8acd304"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
